 /**
 * 文件名称: eeprom.c
 * 摘    要: linux应用程序下操作eeprom源文件
 * 来    源: 自我总结
 *
 * 当前版本: 1.0 
 * 作    者: huenrong
 * 完成日期: 2019年06月12日
 **/


#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <unistd.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>

#include "eeprom.h"

/************************************************************************
函数名称: eeprom_init
函数功能: eeprom设备初始化
函数参数: path_name: 需要打开的eeprom设备路径(形如: /sys/bus/i2c/devices/0-0050/eeprom，不能是/dev/i2c-0)
函数返回: 成功: 返回打开设备的文件描述符
          失败: 返回-1
************************************************************************/
int eeprom_init(const char *path_name)
{
    int fd = -1;
    int ret = -1;
    
    fd = open(path_name, O_RDWR);        // 以可读写方式打开文件(EEPROM)
    if (fd < 0)
    {
        perror("eeprom_init open fail");
        
        return -1;
    }
    
    ret = lseek(fd, 0, SEEK_SET);     // 使用lseek来定位写入数据地址
    if (ret < 0)
    {
        perror("eeprom_init lseek fail");
        
        return -1;
    }
    
    return fd;      // 返回打开设备的文件描述符
}

/************************************************************************
函数名称: eeprom_close
函数功能: eeprom设备关闭
函数参数: fd: 需要关闭的eeprom设备文件描述符
函数返回: 成功: 返回0
          失败: 返回-1
************************************************************************/
int eeprom_close(const int fd)
{
    return close(fd);
}

/************************************************************************
函数名称: eeprom_write_byte
函数功能: 向eeprom指定寄存器写入1byte的数据
函数参数: fd: 需要写入数据的设备的文件描述符
          write_addr: 写入数据的起始寄存器地址
          write_data: 需要写入的数据
函数返回: 成功: 返回0
          失败: 返回-1
************************************************************************/
static int eeprom_write_byte(const int fd, const unsigned short write_addr, const char *write_data)
{
    int ret = -1;

    ret = lseek(fd, write_addr, SEEK_SET);     // 使用lseek来定位写入数据地址
    if (ret < 0)
    {
        perror("eeprom_write_byte lseek fail");

        return -1;
    }

    ret = -1;
    ret = write(fd, write_data, 1);        // 写入数据
    if (ret < 0)
    {
        perror("eeprom_write_byte write fail");

        return -1;
    }

    usleep(4 * 1000);     // 延时4ms(从测试和网上信息查看写EEPROM时，写一个字节需要延时4ms 但是datasheet上的时间不一定是4ms)

    return 0;
}

/************************************************************************
函数名称: eeprom_read_byte
函数功能: 从eeprom指定寄存器读取1byte的数据
函数参数: fd: 需要读取数据的设备的文件描述符
          read_addr: 读取数据的起始寄存器地址
          read_data: 读取到的数据
函数返回: 成功: 返回0
          失败: 返回-1
************************************************************************/
static int eeprom_read_byte(const int fd, const unsigned short read_addr, char *read_data)
{
    int ret = -1;

    ret = lseek(fd, read_addr, SEEK_SET);
    if (ret < 0)
    {
        perror("eeprom_read_byte lseek fail");

        return -1;
    }

    ret = -1;
    ret = read(fd, read_data, 1);
    if (ret < 0)
    {
        perror("eeprom_read_byte read fail");

        return -1;
    }

    return 0;
}

/************************************************************************
函数名称: eeprom_write_nbyte
函数功能: 向eeprom指定寄存器写入指定长度的数据
函数参数: fd: 需要写入数据的设备的文件描述符
          write_addr: 写入数据的起始寄存器地址
          write_data: 需要写入的数据
          write_data_len: 需要写入的数据长度
函数返回: 成功: 返回实际写入的长度
          失败: 返回-1
************************************************************************/
int eeprom_write_nbyte(const int fd, unsigned short write_addr, const char *write_data, const unsigned short write_data_len)
{
    int i = 0;
    int ret = -1;
    int write_num = 0;      // 成功写入的数据长度

    for (i=0; i<write_data_len; i++)
    {
        ret = -1;
        ret = eeprom_write_byte(fd, write_addr, &write_data[i]);     // 写入数据
        if (ret < 0)
        {
            perror("eeprom_write_nbyte write fail");

            return write_num;
        }
        
        write_addr++;       // 写数据成功，寄存器地址向后加1
        write_num++;        // 写数据成功，写入长度加1
    }
	
    return write_num;
}

/************************************************************************
函数名称: eeprom_read_nbyte
函数功能: 从eeprom指定寄存器读取指定长度的数据
函数参数: fd: 需要读取数据的设备的文件描述符
          read_addr: 读取数据的起始寄存器地址
          read_data: 读取到的数据
          read_data_len: 需要读取的数据长度
函数返回: 成功: 返回实际读取的长度
          失败: 返回-1
************************************************************************/
int eeprom_read_nbyte(const int fd, unsigned short read_addr, char *read_data, const unsigned short read_data_len)
{
    int i = 0;
    int ret = -1;
    int read_num = 0;       // 成功读取的数据长度

    for (i=0; i<read_data_len; i++)
    {
        ret = -1;
        ret = eeprom_read_byte(fd, read_addr, &read_data[i]);        // 写入数据
        if (ret < 0)
        {
            perror("eeprom_read_nbyte write fail");

            return read_num;
        }
        
        read_addr++;    // 读数据成功，寄存器地址向后加1
        read_num++;     // 读数据成功，读取长度加1
    }

    return read_num;
}


